
/**
 *******************************************************************************
 * @file timer_driver.h
 * @author .ISS_AUTO (hudandan@issauto.com)
 * @date 2025-03-25  1. 添加 TIM2 定时计数 应用；
 *                   2. 添加 TIM3 PWM 输出应用；
 * @brief
 *
 * @copyright Copyright (c) 2025 ISSAUTO TECH Co., Ltd. All rights reserved.
 *
 *******************************************************************************
 */
/* Includes ------------------------------------------------------------------*/
#include "timer_driver.h"

/* Exported variables --------------------------------------------------------*/
extern RCC_ClocksType sRCC_ClockFreq;

/* Private variables ---------------------------------------------------------*/
#define WATCH_CHAN_MAX_SIZE    WATCH_CHAN_MAX_NUM

static watch_timer_typedef_t debug_watch[WATCH_CHAN_MAX_SIZE];

/* Private functions ---------------------------------------------------------*/
/* PRQA S 3383, 3384 ++ */

/**
 * @brief TimX中断回调
 *
 * @param arg
 */
void Watch_TIMx_Callback(void)
{
    /* Increment overflow count */
    for (size_t i = 0; i < WATCH_CHAN_MAX_NUM; i++) {
        if (debug_watch[i].timerOverflowInterruptCount < 0xFFFFFFFFUL) debug_watch[i].timerOverflowInterruptCount++;
    }
}

/**
 * @brief Clear Time Interval
 *
 * @param watch 窗口指针
 * @return void
 */
void Watch_ClearInterval(watch_timer_channel_e chan)
{
    debug_watch[chan].previousCountValue = TIM2->CNT; //!< Get the current Counter Value in timer ticks representation.
    debug_watch[chan].timerOverflowInterruptCount = 0UL;
}

/**
 * @brief Get Time Interval
 *
 * @param watch 窗口指针
 * @return uint32_t
 */
watch_timer_typedef_t Watch_GetTimeInterval(watch_timer_channel_e chan)
{
    uint32_t counterValue;

    counterValue = TIM2->CNT; // Get the current Counter Value in timer ticks representation.

    if ((counterValue < debug_watch[chan].previousCountValue) && (debug_watch[chan].timerOverflowInterruptCount == 0)) {
        debug_watch[chan].timerOverflowInterruptCount++;
    }

    debug_watch[chan].Period = ((uint32_t)(counterValue + debug_watch[chan].timerOverflowInterruptCount * TIM2_ARR_VALUE - debug_watch[chan].previousCountValue)) / TIM2_PERIOD_US * 1000U ;

    debug_watch[chan].timerOverflowInterruptCount = 0UL;
    debug_watch[chan].previousCountValue = counterValue;

    return debug_watch[chan];
}

/*******************************************************************************
 *                                 TIMER
********************************************************************************/

/**
 * @brief TIM2 Configuration
 * @param None
 * @retval None
 */
void TIM2_Configuration(void)
{
    TIM_TimeBaseInitType TIMx_TimeBaseInitStruct;
    NVIC_InitType NVIC_InitStructure;
    uint32_t PrescalerValue;

    /* TIM2 clock enable */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM2, ENABLE);

    /* Enable the TIM2 global Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0U;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1U;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    /** Compute the prescaler value to have TIM2 counter clock equal to 1000000U Hz
     * Tout(s) = (Prescaler + 1) * (Period + 1) / Tclk(Hz)
     *
     * (Prescaler + 1) = Tout(s) * Tclk(Hz) / (Period + 1)
     * (Prescaler + 1) = (Tout(us) / 1000,000) * Tclk(Hz) / (Period + 1)
     * (Prescaler + 1) = Tout(us) * Tclk(Hz) / 1000,000 / (Period + 1)
     * (Prescaler + 1) = Tclk(Hz) / 1000,000 / ((Period + 1) / Tout(us))
     *
     *  - pclk1div == RCC_HCLK_DIV1 >>> Tclk = Pclk1Freq
     *  - pclk1div != RCC_HCLK_DIV1 >>> Tclk = Pclk1Freq * 2
     *
     */
    PrescalerValue = (sRCC_ClockFreq.Pclk1Freq * 2U) / 1000000U / TIM2_PERIOD_US;

    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIMx_TimeBaseInitStruct);
    TIMx_TimeBaseInitStruct.Period    = (uint16_t)(TIM2_ARR_VALUE - 1U); // 重载值
    TIMx_TimeBaseInitStruct.Prescaler = (uint16_t)(PrescalerValue - 1U);
    // TIMx_TimeBaseInitStruct.ClkDiv    = TIM_CLK_DIV1;
    // TIMx_TimeBaseInitStruct.CntMode   = TIM_CNT_MODE_UP;
    // TIMx_TimeBaseInitStruct.RepetCnt  = 0x0000;

    // TIMx_TimeBaseInitStruct.CapCh1FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapCh2FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapCh3FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapCh4FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapEtrClrFromCompEn = false;
    // TIMx_TimeBaseInitStruct.CapEtrSelFromTscEn  = false;

    TIM_InitTimeBase(TIM2, &TIMx_TimeBaseInitStruct);

    /* TIM2 enable update irq */
    TIM_ConfigInt(TIM2, TIM_INT_UPDATE, ENABLE);

    /* TIM2 enable counter */
    TIM_Enable(TIM2, ENABLE);

}

/**
 * @brief TIM PWM Output Configuration
 * @param pduty - 占空比，取值0~100
 * @retval None
 */
void TIM3_PWM_Configuration(uint16_t pduty)
{
    GPIO_InitType GPIO_InitStructure;

    TIM_TimeBaseInitType TIMx_TimeBaseInitStruct;
    OCInitType TIMx_OCInitStruct;
    uint32_t PrescalerValue;

    /* TIM3 clock enable */
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_TIM3, ENABLE);

    /* GPIOA and GPIOB clock enable */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_AFIO, ENABLE);

    /* GPIOA Configuration:TIM3 Channel 2 as alternate function push-pull */
    GPIO_InitStructure.Pin        = GPIO_PIN_7;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    /* -----------------------------------------------------------------------
    TIM3 Configuration: generate 1 PWM signals with 1 different duty cycles:
    TIM3 Frequency = TIM3 counter clock / (AR + 1)

    TIM3 Channel2 duty cycle = (TIM3_CCR2 / TIM3_ARR) * 100
    ----------------------------------------------------------------------- */
    /* Compute the prescaler value */
    PrescalerValue = (sRCC_ClockFreq.Pclk1Freq * 2U) / TIM3_PWM_CLK_FREQ;

    /* Time base configuration */
    TIM_InitTimBaseStruct(&TIMx_TimeBaseInitStruct);
    TIMx_TimeBaseInitStruct.Period    = (uint16_t)(TIM3_PWM_CLK_FREQ / TIM3_PWM_FREQ) - 1U; //!< AR
    TIMx_TimeBaseInitStruct.Prescaler = (uint16_t)PrescalerValue - 1U;
    // TIMx_TimeBaseInitStruct.ClkDiv    = TIM_CLK_DIV1;
    // TIMx_TimeBaseInitStruct.CntMode   = TIM_CNT_MODE_UP;
    // TIMx_TimeBaseInitStruct.RepetCnt  = 0x0000;

    // TIMx_TimeBaseInitStruct.CapCh1FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapCh2FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapCh3FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapCh4FromCompEn    = false;
    // TIMx_TimeBaseInitStruct.CapEtrClrFromCompEn = false;
    // TIMx_TimeBaseInitStruct.CapEtrSelFromTscEn  = false;

    TIM_InitTimeBase(TIM3, &TIMx_TimeBaseInitStruct);

    /* PWM1 Mode configuration: Channel2 */
    if (pduty > 100) pduty = 100;

    /* OCInitType configuration */
    TIM_InitOcStruct(&TIMx_OCInitStruct);
    // TIMx_OCInitStruct.OcMode      = TIM_FORCED_ACTION_INACTIVE; //!< default set inactive
    TIMx_OCInitStruct.OcMode      = TIM_OCMODE_PWM1; //!< 后续使用时需要设置为PWM1模式: TIM_ConfigForcedOc2(TIM3, TIM_OCMODE_PWM1); TIM_Enable(TIM3, ENABLE);
    TIMx_OCInitStruct.OutputState = TIM_OUTPUT_STATE_ENABLE;
    TIMx_OCInitStruct.Pulse       = TIMx_TimeBaseInitStruct.Period * pduty / 100; //!< Duty= 0%
    TIMx_OCInitStruct.OcPolarity  = TIM_OC_POLARITY_HIGH;

    TIM_InitOc2(TIM3, &TIMx_OCInitStruct);

    /* Preload register configuration on CCDAT2 */
    TIM_ConfigOc2Preload(TIM3, TIM_OC_PRE_LOAD_ENABLE);

    /* Preload register configuration on AR */
    TIM_ConfigArPreload(TIM3, ENABLE);

    /* TIM3 enable counter */
    // TIM_Enable(TIM3, DISABLE); //!< default set disable
    TIM_Enable(TIM3, ENABLE);

}

/* PRQA S 3383, 3384 -- */

/* END OF FILE ---------------------------------------------------------------*/
